#region Microsoft Public License
/*
 * (c) Copyright Chenjun Wu. http://utablesdk.codeplex.com
 * 
 * This source is subject to the Microsoft Public License (Ms-PL).
 * Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
 * All other rights reserved.
 */
#endregion

﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Controls;
using System.Windows;
using System.Windows.Media;

namespace UTable.Objects.Controls
{
    /// <summary>
    /// A container that put the items in grid layout
    /// </summary>
	public class UGridView: ItemsControl, IControl
	{
		#region Private Fields


		#endregion

        #region Constructors

        static UGridView()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(UGridView), new FrameworkPropertyMetadata(typeof(UGridView)));
        }

        public UGridView()
        {
            InitializeIControlPart();
            this.Loaded += new RoutedEventHandler(UGridView_Loaded);
        }

        void UGridView_Loaded(object sender, RoutedEventArgs e)
        {
            ItemsPresenter p = this.GetTemplateChild("PART_ItemsPresenter") as ItemsPresenter;
            Panel = VisualTreeHelper.GetChild(p, 0) as UGridViewPanel;
            Panel.GridView = this;
            Panel.CalculateCells();
            Panel.ArrangeChildren();
        }

        #endregion

        #region Internal Methods

        internal void RaiseItemTappedEvent(UGridViewPanel sender, UGridViewEventArgs args)
        {
            if (ItemTapped != null)
                ItemTapped(sender, args);
        }

        internal void RaiseItemClickedEvent(UGridViewPanel sender, UGridViewEventArgs args)
        {
            if (ItemClicked != null)
                ItemClicked(sender, args);
        }

        internal void RaiseItemLongHoldedEvent(UGridViewPanel sender, UGridViewEventArgs args)
        {
            if (ItemLongHolded != null)
                ItemLongHolded(sender, args);
        }

        internal void RaiseItemDropOutEvent(UGridViewPanel sender, UGridViewEventArgs args)
        {
            if (ItemDropOut != null)
                ItemDropOut(sender, args);
        }

        #endregion

		#region Private Methods

		private static void OnLayoutPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
		{
			(obj as UGridView).OnLayoutPropertyChanged();
		}

		private void OnLayoutPropertyChanged()
		{
			if (Panel != null)
			{
				Panel.CalculateCells();
				Panel.ArrangeChildren();
			}
		}

		#endregion

		#region Properties

		protected UGridViewPanel Panel { get; set; }

        public UGridViewLayoutDirection LayoutDirection
        {
            get { return (UGridViewLayoutDirection)GetValue(LayoutDirectionProperty); }
            set { SetValue(LayoutDirectionProperty, value); }
        }

        public static readonly DependencyProperty LayoutDirectionProperty =
			DependencyProperty.Register("LayoutDirection", typeof(UGridViewLayoutDirection), typeof(UGridView), new UIPropertyMetadata(UGridViewLayoutDirection.LeftRightDown, new PropertyChangedCallback(OnLayoutPropertyChanged)));


        public Thickness LayoutMargin
        {
            get { return (Thickness)GetValue(LayoutMarginProperty); }
            set { SetValue(LayoutMarginProperty, value); }
        }

        public static readonly DependencyProperty LayoutMarginProperty =
			DependencyProperty.Register("LayoutMargin", typeof(Thickness), typeof(UGridView), new UIPropertyMetadata(new Thickness(20, 10, 20, 30), new PropertyChangedCallback(OnLayoutPropertyChanged)));


        public double ItemWidth
        {
            get { return (double)GetValue(ItemWidthProperty); }
            set { SetValue(ItemWidthProperty, value); }
        }

        public static readonly DependencyProperty ItemWidthProperty =
			DependencyProperty.Register("ItemWidth", typeof(double), typeof(UGridView), new UIPropertyMetadata(100.0, new PropertyChangedCallback(OnLayoutPropertyChanged)));


        public double ItemHeight
        {
            get { return (double)GetValue(ItemHeightProperty); }
            set { SetValue(ItemHeightProperty, value); }
        }

        public static readonly DependencyProperty ItemHeightProperty =
			DependencyProperty.Register("ItemHeight", typeof(double), typeof(UGridView), new UIPropertyMetadata(150.0, new PropertyChangedCallback(OnLayoutPropertyChanged)));


        public Thickness CellMargin
        {
            get { return (Thickness)GetValue(CellMarginProperty); }
            set { SetValue(CellMarginProperty, value); }
        }

        public static readonly DependencyProperty CellMarginProperty =
			DependencyProperty.Register("CellMargin", typeof(Thickness), typeof(UGridView), new UIPropertyMetadata(new Thickness(10), new PropertyChangedCallback(OnLayoutPropertyChanged)));


        /// <summary>
        /// Gets or sets the value that indicates whether the item will be removed from the panel when it is dropped outside the panel
        /// </summary>
        public bool DropItemOut
        {
            get { return (bool)GetValue(DropItemOutProperty); }
            set { SetValue(DropItemOutProperty, value); }
        }

        public static readonly DependencyProperty DropItemOutProperty =
            DependencyProperty.Register("DropItemOut", typeof(bool), typeof(UGridView), new UIPropertyMetadata(true));



		public bool AllowItemDrag
		{
			get { return (bool)GetValue(AllowItemDragProperty); }
			set { SetValue(AllowItemDragProperty, value); }
		}

		public static readonly DependencyProperty AllowItemDragProperty =
			DependencyProperty.Register("AllowItemDrag", typeof(bool), typeof(UGridView), new UIPropertyMetadata(true));


		/// <summary>
		/// Gets or sets the value that indicates how the handle the item overflow
		/// </summary>
		public GridViewOverflowMode OverflowMode
		{
			get { return (GridViewOverflowMode)GetValue(OverflowModeProperty); }
			set { SetValue(OverflowModeProperty, value); }
		}

		public static readonly DependencyProperty OverflowModeProperty =
			DependencyProperty.Register("OverflowMode", typeof(GridViewOverflowMode), typeof(UGridView), new UIPropertyMetadata(GridViewOverflowMode.Scroll));


		#endregion

		#region Protected Methods

		public override void OnApplyTemplate()
		{
			base.OnApplyTemplate();
		}

		protected override void OnItemsPanelChanged(ItemsPanelTemplate oldItemsPanel, ItemsPanelTemplate newItemsPanel)
		{
			base.OnItemsPanelChanged(oldItemsPanel, newItemsPanel);
		}

		protected override void OnItemsSourceChanged(System.Collections.IEnumerable oldValue, System.Collections.IEnumerable newValue)
		{
			base.OnItemsSourceChanged(oldValue, newValue);
		}

		protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
		{
			base.PrepareContainerForItemOverride(element, item);
		}

		protected override bool IsItemItsOwnContainerOverride(object item)
		{
			if (item is UGridViewItem)
				return true;
			else
				return false;
		}

		protected override DependencyObject GetContainerForItemOverride()
		{
			return new UGridViewItem();
		}

		#endregion

        #region Events

        public event UGridViewEventHandler ItemTapped;

        public event UGridViewEventHandler ItemClicked;

        public event UGridViewEventHandler ItemLongHolded;

        public event UGridViewEventHandler ItemDropOut;

        #endregion

		#region IControl Implementation
		
		#region Private Fields

        private ControlBaseImpl _impl;

        #endregion

		#region Private Methods

		private void InitializeIControlPart()
        {
			_impl = new ControlBaseImpl(this);
            _impl.GotFingerCapture += new UTable.Input.MultiTouch.FingerEventHandler(_impl_GotFingerCapture);
            _impl.LostFingerCapture += new UTable.Input.MultiTouch.FingerEventHandler(_impl_LostFingerCapture);
			this.InputReceived += new UTable.Input.InputEventHandler(_impl_InputReceived);
        }

        void _impl_InputReceived(UTable.Input.InputEventArgs args)
        {
			if (args is UTable.Input.MultiTouch.MultiTouchEventArgs)
				MultiTouchProcessor.RaiseMultiTouchEvent(args as UTable.Input.MultiTouch.MultiTouchEventArgs);
        }

        void _impl_LostFingerCapture(object sender, UTable.Input.MultiTouch.FingerEventArgs args)
        {
            if (LostFingerCapture != null)
                LostFingerCapture(sender, args);
        }

        void _impl_GotFingerCapture(object sender, UTable.Input.MultiTouch.FingerEventArgs args)
        {
            if (GotFingerCapture != null)
                GotFingerCapture(sender, args);
        }

        #endregion

        #region IControl Members

        public UTable.Objects.Controls.ControlInfo Info
        {
            get { return _impl.Info; }
        }
		
		public UTable.Objects.Handlers.MultiTouchProcessor MultiTouchProcessor 
		{ 
			get { return _impl.MultiTouchProcessor; } 
		}

        #endregion

        #region IVisualNode Members

        public String ID
        {
            get { return _impl.ID; }
        }

        public new double Width
        {
            get { return _impl.Width; }
            set { _impl.Width = value; }
        }

        public new double Height
        {
            get { return _impl.Height; }
            set { _impl.Height = value; }
        }

        public new bool IsHitTestVisible
        {
            get { return _impl.IsHitTestVisible; }
            set { _impl.IsHitTestVisible = value; }
        }

        #endregion

        #region IInputNode Members

        public void RaiseEvent(UTable.Input.InputEventArgs e)
        {
            if (InputReceived != null)
            {
                InputReceived(e);
            }
            OnInputReceived(e);
        }

        public virtual void OnInputReceived(UTable.Input.InputEventArgs args)
        {
            _impl.OnInputReceived(args);
        }

        public bool CaptureFinger(int fingerId)
        {
            return _impl.CaptureFinger(fingerId);
        }

        public bool UncaptureFinger(int fingerId)
        {
            return _impl.UncaptureFinger(fingerId);
        }

        public event UTable.Input.MultiTouch.FingerEventHandler GotFingerCapture;

        public event UTable.Input.MultiTouch.FingerEventHandler LostFingerCapture;

        public event UTable.Input.InputEventHandler InputReceived;

        #endregion
        #endregion
	}

	public enum GridViewOverflowMode
	{
		/// <summary>
		/// Use a UScrollViewer to scroll the content of the grid view if the item is overflow
		/// </summary>
		Scroll,

		/// <summary>
		/// Divide the content of the grid view into several pages, 
		/// and use a UPieViewer to turn the pages 
		/// </summary>
		Turn,
	}

    public delegate void UGridViewEventHandler(UGridViewPanel sender, UGridViewEventArgs args);

    public class UGridViewEventArgs
    {
        public UGridViewEventArgs(UGridViewItem item, Point position)
        {
            Item = item;
            Position = position;
        }

        /// <summary>
        /// the item that relates to the event
        /// </summary>
        public UGridViewItem Item { get; set; }

        /// <summary>
        /// The position of the item when the event occurred
        /// </summary>
        public Point Position { get; set; }
    }
}
